﻿using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Foundation.Collections;

namespace Septagon.App.WildTunnel.Common
{
	/// <summary>
	/// IObservableMap の実装では、既定のビュー モデルとして使用するため、再入をサポート
	/// しています。
	/// </summary>
	public class ObservableDictionary : IObservableMap<string, object>
	{
		private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<string>
		{
			public ObservableDictionaryChangedEventArgs(CollectionChange change, string key)
			{
				this.CollectionChange = change;
				this.Key = key;
			}

			public CollectionChange CollectionChange { get; private set; }
			public string Key { get; private set; }
		}

		private Dictionary<string, object> _dictionary = new Dictionary<string, object>();
		public event MapChangedEventHandler<string, object> MapChanged;

		private void InvokeMapChanged(CollectionChange change, string key)
		{
			var eventHandler = MapChanged;
			if (eventHandler != null)
			{
				eventHandler(this, new ObservableDictionaryChangedEventArgs(change, key));
			}
		}

		public void Add(string key, object value)
		{
			this._dictionary.Add(key, value);
			this.InvokeMapChanged(CollectionChange.ItemInserted, key);
		}

		public void Add(KeyValuePair<string, object> item)
		{
			this.Add(item.Key, item.Value);
		}

		public bool Remove(string key)
		{
			if (this._dictionary.Remove(key))
			{
				this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
				return true;
			}
			return false;
		}

		public bool Remove(KeyValuePair<string, object> item)
		{
			object currentValue;
			if (this._dictionary.TryGetValue(item.Key, out currentValue) &&
				Object.Equals(item.Value, currentValue) && this._dictionary.Remove(item.Key))
			{
				this.InvokeMapChanged(CollectionChange.ItemRemoved, item.Key);
				return true;
			}
			return false;
		}

		public object this[string key]
		{
			get
			{
				return this._dictionary[key];
			}
			set
			{
				this._dictionary[key] = value;
				this.InvokeMapChanged(CollectionChange.ItemChanged, key);
			}
		}

		public void Clear()
		{
			var priorKeys = this._dictionary.Keys.ToArray();
			this._dictionary.Clear();
			foreach (var key in priorKeys)
			{
				this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
			}
		}

		public ICollection<string> Keys
		{
			get { return this._dictionary.Keys; }
		}

		public bool ContainsKey(string key)
		{
			return this._dictionary.ContainsKey(key);
		}

		public bool TryGetValue(string key, out object value)
		{
			return this._dictionary.TryGetValue(key, out value);
		}

		public ICollection<object> Values
		{
			get { return this._dictionary.Values; }
		}

		public bool Contains(KeyValuePair<string, object> item)
		{
			return this._dictionary.Contains(item);
		}

		public int Count
		{
			get { return this._dictionary.Count; }
		}

		public bool IsReadOnly
		{
			get { return false; }
		}

		public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
		{
			return this._dictionary.GetEnumerator();
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return this._dictionary.GetEnumerator();
		}

		public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
		{
			int arraySize = array.Length;
			foreach (var pair in this._dictionary)
			{
				if (arrayIndex >= arraySize) break;
				array[arrayIndex++] = pair;
			}
		}
	}
}
